package common.fattree;

import common.Device;
import common.PortInterface;
import common.correspondence.CountWrap;
import common.correspondence.Message;
import common.proto.out.CountMessage;

import java.io.*;

public class DebugPort extends Thread implements PortInterface {
    static String streamBufferPath = "temp/";
    Device device;
    String name;
    String inputFile;
    ByteArrayOutputStream output;
    public FattreeDevice.DeviceType linkType;
    boolean already;

    public DebugPort(String name, Device device, FattreeDevice.DeviceType dt){
        this.name = name;
        this.device = device;
        String[] token = name.split(">");
        this.inputFile = "temp/" + token[1] + "!" + token[0];

        linkType = dt;
        output = new ByteArrayOutputStream();
        already = false;
        checkPath();
    }

    @Override
    public void send(Message msg) {
        try {
//            System.out.println(msg.message.getSerializedSize());
            output.write(intToBytes(msg.type.ordinal()));
            output.write(intToBytes(msg.message.getSerializedSize()));
            msg.message.writeTo(output);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void receive(Message msg) {

    }

    @Override
    public void close() {
        String[] token = name.split(">");
        File file = checkFile(token[0] + "!" + token[1]);
        try {
            OutputStream os = new FileOutputStream(file);
            output.writeTo(os);
            os.flush();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean isAlready() {
        return already;
    }

    @Override
    public void testLink() {

    }

    @Override
    public String toString() {
        return name;
    }

    public void run(){
        File file = new File(inputFile);
        if(!file.exists() || !file.isFile()) return;
        try {
            InputStream is = new FileInputStream(file);
            while (true) {
                boolean flag = false;
                int headerRead = 0;
                byte[] header = new byte[8];
                int readLen;
                while (headerRead < 8){
                    readLen = is.read(header, headerRead, 8- headerRead);
                    if(readLen == -1) {
                        flag = true;
                        if(headerRead != 0) System.err.println(name + " error read");
                        break;
                    };
                    headerRead += readLen;
                }
                if (flag) break;
                long time = System.nanoTime();
                int length = byteArrayToInt(header, 4);
                int rec = 0;
                byte[] content = new byte[length];
                while(rec < length){
                    readLen = is.read(content, rec, length-rec);
                    if(readLen == -1) {
                        System.err.println("shut while read");
                        flag = true;
                        break;
                    }
                    rec += readLen;
                }
                if (flag) break;
                long t1 = System.nanoTime();
                CountMessage.CountResult c = CountWrap.messageToCountResult(content);
                long t2 = System.nanoTime();
                device.addRecord(c.getId(), c.getDestinationNodeIndex(), "deserialization", t2-t1);
                device.receiveCount(c, name, time);
            }
            is.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
        file.delete();
        already = true;
    }

    public void checkPath(){
        File file = new File(streamBufferPath);
        if(!file.exists() || !file.isDirectory()){
            if(!file.mkdir()) System.err.println("mkdir failed.");
        }
    }
    public File checkFile(String path){
        File file = new File(streamBufferPath + path);
        if(!file.exists() || !file.isFile()){
            try {
                if(!file.createNewFile()) System.err.println("mkdir failed.");

            } catch (IOException e) {
                System.err.println(file.getAbsolutePath());
                e.printStackTrace();
            }
        }
        return file;
    }
    private static byte[] intToBytes(int a){
        byte[] b = new byte[4];
        b[0] = (byte)((a >> 24) & 0xFF);
        b[1] = (byte)((a >> 16) & 0xFF);
        b[2] = (byte)((a >>  8) & 0xFF);
        b[3] = (byte)((a      ) & 0xFF);
        return b;
    }

    public static int byteArrayToInt(byte[] bytes, int start) {
        int value=0;
        for(int i = 0; i < 4; i++) {
            value <<= 8;
            value |= (bytes[start+i] & 0xFF);
        }
        return value;
    }
}
